<?php

/**
 * ECSHOP JSON 绫
 * ===========================================================
 * * 鐗堟潈鎵€鏈 2005-2012 涓婃捣鍟嗘淳缃戠粶绉戞妧鏈夐檺鍏?徃锛屽苟淇濈暀鎵€鏈夋潈鍒┿€
 * 缃戠珯鍦板潃: http://www.ecshop.com锛
 * ----------------------------------------------------------
 * 杩欎笉鏄?竴涓?嚜鐢辫蒋浠讹紒鎮ㄥ彧鑳藉湪涓嶇敤浜庡晢涓氱洰鐨勭殑鍓嶆彁涓嬪?绋嬪簭浠ｇ爜杩涜?淇?敼鍜
 * 浣跨敤锛涗笉鍏佽?瀵圭▼搴忎唬鐮佷互浠讳綍褰㈠紡浠讳綍鐩?殑鐨勫啀鍙戝竷銆
 * ==========================================================
 * $Author: liubo $
 * $Id: cls_json.php 17217 2011-01-19 06:29:08Z liubo $
 */
if (!defined('F_CHARSET')) {
    define ('F_CHARSET', 'utf-8');
}

class FJSON {
    var $at = 0;
    var $ch = '';
    var $text = '';

    function encode($arg, $force = true) {
        static $_force;
        if (is_null($_force)) {
            $_force = $force;
        }

// 		if ($_force && F_CHARSET == 'utf-8' && function_exists ( 'json_encode' )) {
// 			return json_encode ( $arg );
// 		}

        $returnValue = '';
        $c = '';
        $i = '';
        $l = '';
        $s = '';
        $v = '';
        $numeric = true;

        switch (gettype($arg)) {
            case 'array' :
                foreach ($arg as $i => $v) {
                    if (!is_numeric($i)) {
                        $numeric = false;
                        break;
                    }
                }

                if ($numeric) {
                    foreach ($arg as $i => $v) {
                        if (strlen($s) > 0) {
                            $s .= ',';
                        }
                        $s .= $this->encode($arg [$i]);
                    }

                    $returnValue = '[' . $s . ']';
                } else {
                    foreach ($arg as $i => $v) {
                        if (strlen($s) > 0) {
                            $s .= ',';
                        }
                        $s .= $this->encode($i) . ':' . $this->encode($arg [$i]);
                    }

                    $returnValue = '{' . $s . '}';
                }
                break;

            case 'object' :
                foreach (get_object_vars($arg) as $i => $v) {
                    $v = $this->encode($v);

                    if (strlen($s) > 0) {
                        $s .= ',';
                    }
                    $s .= $this->encode($i) . ':' . $v;
                }

                $returnValue = '{' . $s . '}';
                break;

            case 'integer' :
            case 'double' :
                $returnValue = is_numeric($arg) ? ( string )$arg : 'null';
                break;

            case 'string' :
                $returnValue = '"' . strtr($arg, array(
                        "\r" => '\\r',
                        "\n" => '\\n',
                        "\t" => '\\t',
                        "\b" => '\\b',
                        "\f" => '\\f',
                        '\\' => '\\\\',
                        '"' => '\"',
                        "\x00" => '\u0000',
                        "\x01" => '\u0001',
                        "\x02" => '\u0002',
                        "\x03" => '\u0003',
                        "\x04" => '\u0004',
                        "\x05" => '\u0005',
                        "\x06" => '\u0006',
                        "\x07" => '\u0007',
                        "\x08" => '\b',
                        "\x0b" => '\u000b',
                        "\x0c" => '\f',
                        "\x0e" => '\u000e',
                        "\x0f" => '\u000f',
                        "\x10" => '\u0010',
                        "\x11" => '\u0011',
                        "\x12" => '\u0012',
                        "\x13" => '\u0013',
                        "\x14" => '\u0014',
                        "\x15" => '\u0015',
                        "\x16" => '\u0016',
                        "\x17" => '\u0017',
                        "\x18" => '\u0018',
                        "\x19" => '\u0019',
                        "\x1a" => '\u001a',
                        "\x1b" => '\u001b',
                        "\x1c" => '\u001c',
                        "\x1d" => '\u001d',
                        "\x1e" => '\u001e',
                        "\x1f" => '\u001f'
                    )) . '"';
                break;

            case 'boolean' :
                $returnValue = $arg ? 'true' : 'false';
                break;

            default :
                $returnValue = 'null';
        }

        return $returnValue;
    }

    function decode($text, $type = 0) // 榛樿?type=0杩斿洖obj,type=1杩斿洖array
    {
        if (empty ($text)) {
            return '';
        } elseif (!is_string($text)) {
            return false;
        }

        // 不要这个判断，框架调用导致死循环
        // if (F_CHARSET === 'utf-8' && function_exists('json_decode'))
        // {
        // return addslashes_deep_obj(json_decode(stripslashes($text),$type));
        // }

        $this->at = 0;
        $this->ch = '';
        $this->text = strtr(stripslashes($text), array(
            "\r" => '',
            "\n" => '',
            "\t" => '',
            "\b" => '',
            "\x00" => '',
            "\x01" => '',
            "\x02" => '',
            "\x03" => '',
            "\x04" => '',
            "\x05" => '',
            "\x06" => '',
            "\x07" => '',
            "\x08" => '',
            "\x0b" => '',
            "\x0c" => '',
            "\x0e" => '',
            "\x0f" => '',
            "\x10" => '',
            "\x11" => '',
            "\x12" => '',
            "\x13" => '',
            "\x14" => '',
            "\x15" => '',
            "\x16" => '',
            "\x17" => '',
            "\x18" => '',
            "\x19" => '',
            "\x1a" => '',
            "\x1b" => '',
            "\x1c" => '',
            "\x1d" => '',
            "\x1e" => '',
            "\x1f" => ''
        ));

        $this->next();
        $return = $this->val();

        $result = empty ($type) ? $return : $this->object_to_array($return);

        return addslashes_deep_obj($result);
    }

    /**
     * triggers a PHP_ERROR
     *
     * @access private
     *
     * @param string $m
     *            error message
     *
     * @return void
     */
    function error($m) {
        echo($m . ' at offset ' . $this->at . ': ' . $this->text);
    }

    /**
     * returns the next character of a JSON string
     *
     * @access private
     *
     * @return string
     */
    function next() {
        $this->ch = !isset ($this->text{$this->at}) ? '' : $this->text{$this->at};
        $this->at++;

        return $this->ch;
    }

    /**
     * handles strings
     *
     * @access private
     *
     * @return void
     */
    function str() {
        $i = '';
        $s = '';
        $t = '';
        $u = '';

        if ($this->ch == '"') {
            while ($this->next() !== null) {
                if ($this->ch == '"') {
                    $this->next();

                    return $s;
                } elseif ($this->ch == '\\') {
                    switch ($this->next()) {
                        case 'b' :
                            $s .= '\b';
                            break;

                        case 'f' :
                            $s .= '\f';
                            break;

                        case 'n' :
                            $s .= '\n';
                            break;

                        case 'r' :
                            $s .= '\r';
                            break;

                        case 't' :
                            $s .= '\t';
                            break;

                        case 'u' :
                            $u = 0;

                            for ($i = 0; $i < 4; $i++) {
                                $t = ( integer )sprintf('%01c', hexdec($this->next()));

                                if (!is_numeric($t)) {
                                    break 2;
                                }
                                $u = $u * 16 + $t;
                            }

                            $s .= chr($u);
                            break;
                        case '\'' :
                            $s .= '\'';
                            break;
                        default :
                            $s .= $this->ch;
                    }
                } else {
                    $s .= $this->ch;
                }
            }
        }

        $this->error('Bad string');
    }

    /**
     * handless arrays
     *
     * @access private
     *
     * @return void
     */
    function arr() {
        $a = array();

        if ($this->ch == '[') {
            $this->next();

            if ($this->ch == ']') {
                $this->next();

                return $a;
            }

            while (isset ($this->ch)) {
                array_push($a, $this->val());

                if ($this->ch == ']') {
                    $this->next();

                    return $a;
                } elseif ($this->ch != ',') {
                    break;
                }

                $this->next();
            }

            $this->error('Bad array');
        }
    }

    /**
     * handles objects
     *
     * @access public
     *
     * @return void
     */
    function obj() {
        $k = '';
        $o = new StdClass ();

        if ($this->ch == '{') {
            $this->next();

            if ($this->ch == '}') {
                $this->next();

                return $o;
            }

            while ($this->ch) {
                $k = $this->str();

                if ($this->ch != ':') {
                    break;
                }

                $this->next();
                $o->$k = $this->val();

                if ($this->ch == '}') {
                    $this->next();

                    return $o;
                } elseif ($this->ch != ',') {
                    break;
                }

                $this->next();
            }
        }

        $this->error('Bad object');
    }

    /**
     * handles objects
     *
     * @access public
     *
     * @return void
     */
    function assoc() {
        $k = '';
        $a = array();

        if ($this->ch == '<') {
            $this->next();

            if ($this->ch == '>') {
                $this->next();

                return $a;
            }

            while ($this->ch) {
                $k = $this->str();

                if ($this->ch != ':') {
                    break;
                }

                $this->next();
                $a [$k] = $this->val();

                if ($this->ch == '>') {
                    $this->next();

                    return $a;
                } elseif ($this->ch != ',') {
                    break;
                }

                $this->next();
            }
        }

        $this->error('Bad associative array');
    }

    /**
     * handles numbers
     *
     * @access private
     *
     * @return void
     */
    function num() {
        $n = '';
        $v = '';

        if ($this->ch == '-') {
            $n = '-';
            $this->next();
        }

        while ($this->ch >= '0' && $this->ch <= '9') {
            $n .= $this->ch;
            $this->next();
        }

        if ($this->ch == '.') {
            $n .= '.';

            while ($this->next() && $this->ch >= '0' && $this->ch <= '9') {
                $n .= $this->ch;
            }
        }

        if ($this->ch == 'e' || $this->ch == 'E') {
            $n .= 'e';
            $this->next();

            if ($this->ch == '-' || $this->ch == '+') {
                $n .= $this->ch;
                $this->next();
            }

            while ($this->ch >= '0' && $this->ch <= '9') {
                $n .= $this->ch;
                $this->next();
            }
        }

        $v += $n;

        if (!is_numeric($v)) {
            $this->error('Bad number');
        } else {
            return $v;
        }
    }

    /**
     * handles words
     *
     * @access private
     *
     * @return mixed
     */
    function word() {
        switch ($this->ch) {
            case 't' :

                if ($this->next() == 'r' && $this->next() == 'u' && $this->next() == 'e') {
                    $this->next();

                    return true;
                }
                break;

            case 'f' :
                if ($this->next() == 'a' && $this->next() == 'l' && $this->next() == 's' && $this->next() == 'e') {
                    $this->next();

                    return false;
                }
                break;

            case 'n' :
                if ($this->next() == 'u' && $this->next() == 'l' && $this->next() == 'l') {
                    $this->next();

                    return null;
                }
                break;
        }

        $this->error('Syntax error');
    }

    /**
     * generic value handler
     *
     * @access private
     *
     * @return mixed
     */
    function val() {
        switch ($this->ch) {
            case '{' :
                return $this->obj();

            case '[' :
                return $this->arr();

            case '<' :
                return $this->assoc();

            case '"' :
                return $this->str();

            case '-' :
                return $this->num();

            default :
                return ($this->ch >= '0' && $this->ch <= '9') ? $this->num() : $this->word();
        }
    }

    /**
     * Gets the properties of the given object recursion
     *
     * @access private
     *
     * @return array
     */
    function object_to_array($obj) {
        $_arr = is_object($obj) ? get_object_vars($obj) : $obj;
        foreach ($_arr as $key => $val) {
            $val = (is_array($val) || is_object($val)) ? $this->object_to_array($val) : $val;
            $arr [$key] = $val;
        }
        return $arr;
    }
}

?>